home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Leisure Game Pak
/
Leisure Game Pak.iso
/
lpgame1
/
04
/
source
/
mynesplf.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-08-17
|
15KB
|
411 lines
(* ..................................................................... *)
(* : file : MYNESPLF.PAS : *)
(* : contents : the playfield routines for MYNES! : *)
(* : last update : 30-JUN-93 : *)
(* :...................:...............................................: *)
(*
- draw_playfield, restore_playfield, generate_playfield
- draw_color_bar, refresh_bar
- real_col, real_row
- explode ... lets the playfield explode
- some general purpose routines (max, in_rect)
*)
(* calculate the maximum of two integers/words/bytes/longints *)
FUNCTION max(a, b : LONGINT) : LONGINT;
BEGIN
IF (a > b) THEN max := a ELSE max := b;
END; (* max *)
(* in_rect(x,y,x1,y1,dx,dy) <=> (x,y) is in (x1,y1)-(x1+dx-1, y1+dy-1) *)
FUNCTION in_rect(x, y, x1, y1, dx, dy : INTEGER) : BOOLEAN;
BEGIN
in_rect := (x >= x1) AND (x < x1+dx) AND (y >= y1) AND (y < y1+dy);
END; (* in_rect *)
(* real_col, real_row return the real coords of a tile that is out of bounds *)
FUNCTION real_col(VAR scene : SCENE_TYPE;
col : COL_ROW_TYPE) : COL_ROW_TYPE;
BEGIN
real_col := (scene.NumCols + col) MOD scene.NumCols;
END; (* real_col *)
FUNCTION real_row(VAR scene : SCENE_TYPE;
row : COL_ROW_TYPE) : COL_ROW_TYPE;
BEGIN
real_row := (scene.NumRows + row) MOD scene.NumRows;
END; (* real_row *)
PROCEDURE refresh_bar(b: COORDS_TYPE; act_val, max_val : LONGINT);
VAR newlen : WORD;
BEGIN
HideMouse;
(* check range *)
IF (act_val < 0) THEN
newlen := 0
ELSE IF (act_val > max_val) THEN
newlen := COLBAR_LEN
ELSE
(* COLBAR_LEN * act_val would overflow if act_val wasn't LONGINT *)
newlen := (COLBAR_LEN * act_val) DIV max_val;
SetFillStyle(SOLIDFILL, BLACK);
Bar(b.x + newlen, SUCC(b.y), b.x + COLBAR_LEN, b.y + SUCC(COLBAR_HEIGHT));
SetColor(GREY);
Line(b.x + newlen, b.y, b.x + COLBAR_LEN, b.y);
ShowMouse;
END; (* refresh_bar *)
PROCEDURE draw_color_bar(b : COORDS_TYPE);
VAR z : WORD;
BEGIN
SetFillStyle(SOLIDFILL, BLACK);
Bar(b.x + 2, SUCC(b.y),
b.x + SUCC(COLBAR_LEN), b.y + SUCC(COLBAR_HEIGHT));
FOR z := 0 TO PRED(COLBAR_HEIGHT) DIV 2 DO
BEGIN
SetColor(CLR_VISIBLE1 + z);
Line(b.x, b.y + z, b.x + PRED(COLBAR_LEN), b.y + z);
Line(b.x, b.y + PRED(COLBAR_HEIGHT) - z,
b.x + PRED(COLBAR_LEN), b.y + PRED(COLBAR_HEIGHT) - z);
END; (* FOR *)
END; (* draw_color_bar *)
(* draw_playfield draws the complete playfield, invoked only once per game *)
PROCEDURE draw_playfield(scene : SCENE_TYPE);
CONST control_x = 8;
control_y = 423;
VAR col, row, row_n : COL_ROW_TYPE;
r_step : SHORTINT;
myFrame : FRAME_TYPE;
BEGIN
dim_palette(0, SLOW_DIM);
HideMouse; (* heavy graphics ahead ... *)
generate_tile(scene, play_tile);
SetFillStyle(SolidFill, GREY); Bar(0, 0, GetMaxX, GetMaxY);
(* draw game-frame with black interior *)
myFrame.init(PRED(scene.Origin.x), PRED(scene.Origin.y),
1 + SUCC(scene.Size.x) * scene.NumCols,
1 + SUCC(scene.Size.y) * scene.NumRows,
THICKWIDTH, BLACK, DKGREY, WHITE, GAD_NOT_PUSHED, TRUE);
myFrame.show;
(* draw control-frame with grey interior *)
myFrame.init(control_x, control_y, 624, 52,
NORMWIDTH, GREY, DKGREY, WHITE, GAD_NOT_PUSHED, TRUE);
myFrame.show;
ShadowTextXY(control_x + 8, control_y + 12, WHITE, BLACK, 'TIME');
draw_color_bar(TIME_BAR);
ShadowTextXY(control_x + 8, control_y + 35, WHITE, BLACK, 'DONE');
draw_color_bar(DONE_BAR);
IF (GameStatus = PLAY) THEN
BEGIN
GAME_PAUSE_GADGET.show;
GAME_QUIT_GADGET.show;
GAME_DEMO_GADGET.show;
END; (* IF *)
dim_palette(100, SLOW_DIM);
(* NumCols even -> 0 ... (NumCols / 2) - 1
" odd -> 0 ... (NumCols-1 / 2) *)
FOR col:=0 TO PRED(scene.NumCols) DIV 2 DO
BEGIN
(* ziczac graphics *)
IF ODD(col) THEN
BEGIN
row_n := 0; row := PRED(scene.NumRows); r_step :=-1;
END (* IF *)
ELSE BEGIN
row := 0; row_n := PRED(scene.NumRows); r_step := 1;
END; (* ELSE *)
WHILE (row <> row_n + r_step) DO
BEGIN
draw_tile(scene, play_tile, col, row, hidden0);
draw_tile(scene, play_tile,
PRED(scene.NumCols) - col,
PRED(scene.NumRows) - row, hidden0);
INC(row, r_step);
END; (* WHILE *)
END; (* FOR col *)
ShowMouse;
END; (* draw_field *)
(* restore_playfield hides visible and marked tiles *)
(* necessary if you want to play the field AGAIN *)
{ it is in comments since we don't use it ...
PROCEDURE restore_playfield(scene : SCENE_TYPE);
VAR col, row : COL_ROW_TYPE;
BEGIN
FOR row := 0 TO PRED(scene.NumRows) DO
BEGIN
FOR col := 0 TO PRED(scene.NumCols) DO
BEGIN
(* hide visible and marked tiles *)
IF (playfield[row,col] IN VISIBLE) THEN
DEC(playfield[row,col], ORD(visible0) - ORD(hidden0))
ELSE IF (playfield[row,col] IN MARKED) THEN
DEC(playfield[row,col], ORD(marked0) - ORD(hidden0));
END; (* FOR col *)
END; (* FOR row *)
END; (* restore_playfield *)
}
PROCEDURE generate_playfield(scene : SCENE_TYPE);
VAR col, colj, r_col,
row, rowi, r_row : COL_ROW_TYPE;
mines_to_put : BYTE;
BEGIN (* generate_playfield *)
(* initialize playfield with hidden0's *)
FOR row := 0 TO PRED(scene.NumRows) DO
FOR col := 0 TO PRED(scene.NumCols) DO
playfield[row, col] := hidden0;
mines_to_put := scene.NumMines;
REPEAT
col := Random(scene.NumCols);
row := Random(scene.NumRows);
IF (playfield[row, col] <> hidden_mine) THEN
BEGIN
DEC(mines_to_put);
playfield[row, col] := hidden_mine;
(* increase counters around the mine *)
(* note that the playfield is a circular one, i.e.
left and right, upper and lower edges butt together *)
FOR rowi := PRED(row) TO SUCC(row) DO
BEGIN
r_row := real_row(scene, rowi);
FOR colj := PRED(col) TO SUCC(col) DO
BEGIN
r_col := real_col(scene, colj);
(* don't increase hidden_mines *)
IF (playfield[r_row, r_col] IN [hidden0..hidden7]) THEN
INC(playfield[r_row, r_col]);
END; (* FOR colj *)
END; (* FOR rowi *)
END; (* IF *)
UNTIL (mines_to_put = 0);
END; (* generate_playfield *)
(* explode with its subroutines handles the complete 'BLASTED' event *)
PROCEDURE explode(VAR scene : SCENE_TYPE;
col, row : COL_ROW_TYPE);
VAR mines : ARRAY[1..MAX_MINES] OF
RECORD
col, row : COL_ROW_TYPE; (* the 'home' tile *)
x, y : WORD; (* center of this tile *)
age : BYTE; (* the phase *)
END;
first_mine, last_mine,
width, height : WORD; (* size of the scene, both -1 *)
PROCEDURE add_mine(VAR scene : SCENE_TYPE;
col, row : COL_ROW_TYPE);
VAR x, y : WORD;
BEGIN
INC(last_mine);
mines[last_mine].col := col;
mines[last_mine].row := row;
get_tile_middle(scene, col, row, x, y);
mines[last_mine].x := x - scene.Origin.x;
mines[last_mine].y := y - scene.Origin.y;
mines[last_mine].age := 0;
END; (* add_mine *)
PROCEDURE draw_block(x1, y1, x2, y2 : INTEGER; color : BYTE);
VAR bl : ARRAY[1..4] OF (* a block may split up into 4 blocks *)
RECORD
x1, y1, x2, y2 : INTEGER;
END;
i, num_bl, start : BYTE;
BEGIN
(* first: normalize coordinates, so that (x2,y2) in playfield *)
IF (x2 >= width) THEN
BEGIN
DEC(x2, width); DEC(x1, width);
END;
IF (y2 >= height) THEN
BEGIN
DEC(y2, height); DEC(y1, height);
END;
bl[1].x1 := x1; bl[1].y1 := y1; bl[1].x2 := x2; bl[1].y2 := y2;
bl[2] := bl[1];
IF (x1 < 0) THEN
BEGIN
(* draw 2 blocks, one on the left, one on the right edge *)
start := 1; num_bl := 2;
bl[1].x1 := 0;
bl[2].x1 := width + x1;
bl[2].x2 := PRED(width);
END
ELSE BEGIN
start := 3; num_bl := 1;
bl[3] := bl[1];
END;
IF (y1 < 0) THEN
BEGIN
(* draw 2*num_bl blocks, num_bl on the upper, num_bl on the lower edge *)
FOR i := 1 TO 2 DO
BEGIN
(* copy the blocks 1, 2 onto 3, 4 *)
bl[2 + i] := bl[i];
bl[1 + i].y1 := 0;
bl[i * i].y1 := height + y1;
bl[i * i].y2 := PRED(height);
END; (* FOR *)
INC(num_bl, num_bl);
END; (* IF *)
SetFillStyle(SOLIDFILL, color);
FOR i := start TO start + PRED(num_bl) DO
Bar(bl[i].x1, bl[i].y1, bl[i].x2, bl[i].y2);
END; (* draw_block *)
PROCEDURE gather_hidden_mines(VAR scene : SCENE_TYPE;
col, row, delta : COL_ROW_TYPE);
VAR colj, rowi,
r_col, r_row : COL_ROW_TYPE;
cont_val : WORD;
contents : CONTENTS_TYPE;
BEGIN
FOR rowi := row - delta TO row + delta DO
BEGIN
r_row := real_row(scene, rowi);
FOR colj := col - delta TO col + delta DO
BEGIN
r_col := real_col(scene, colj);
contents := playfield[r_row, r_col];
IF (contents IN [visible1..visible8]) THEN
BEGIN (* decrease the score *)
cont_val := ORD(contents) - ORD(visible0);
IF (Score > cont_val) THEN
DEC(Score, cont_val)
ELSE
Score := 0;
(* hide this tile, so that
the score won't be decreased again as
the explosion continues #22.11.92 *)
DEC(playfield[r_row, r_col], ORD(visible0)-ORD(hidden0));
END (* IF *)
ELSE IF (contents = hidden_mine) THEN
BEGIN
(* show mine so that it won't explode again *)
playfield[r_row, r_col] := visible_mine;
(* only HIDDEN mines will explode, marked mines won't *)
add_mine(scene, r_col, r_row);
END; (* IF *)
END; (* FOR *)
END; (* FOR *)
END; (* gather_hidden_mines *)
(* constants and variables local only in explosion *)
CONST oldest_age = 7;
VAR x1, y1, x2, y2,
dist_down, dist_right,
dist_up, dist_left : INTEGER;
dist_x, dist_y : ARRAY[0..oldest_age] OF INTEGER;
color : BYTE;
mine, t,
xp, yp, xm, ym : WORD;
BEGIN (* explode *)
HideMouse;
(* calculate the size of the explosions *)
get_tile_pos(scene, 0, 0, xp, yp);
get_tile_middle(scene, 0, 0, xm, ym);
dist_left := xm - xp;
dist_right := scene.Size.x - dist_left;
dist_up := ym - yp;
dist_down := scene.Size.y - dist_up;
FOR t := 0 TO oldest_age DO
BEGIN
dist_x[t] := SUCC(scene.Size.x) * (t SHR 1);
dist_y[t] := SUCC(scene.Size.y) * (t SHR 1);
END; (* FOR *)
width := PRED(SUCC(scene.Size.x) * scene.NumCols);
height:= PRED(SUCC(scene.Size.y) * scene.NumRows);
SetViewPort(scene.Origin.x, scene.Origin.y,
scene.Origin.x + width, scene.Origin.y + height, ClipOFF);
first_mine := 1; (* no mines removed yet *)
last_mine := 0; (* no mines added yet *)
add_mine(scene, col, row);
REPEAT
(* use a WHILE-loop instead of FOR, since last_mine is being
altered during the loop *)
mine := first_mine;
WHILE (mine <= last_mine) DO
BEGIN
WITH mines[mine] DO (* col, row, x, y, age *)
BEGIN
IF (SoundIsON) THEN
Sound(age * 8 + 20);
x1 := x - (dist_x[age] + (age AND 1) * dist_left);
y1 := y - (dist_y[age] + (age AND 1) * dist_up);
x2 := x + (dist_x[age] + (age AND 1) * dist_right);
y2 := y + (dist_y[age] + (age AND 1) * dist_down);
(* colors are clr_visible2..clr_visible7, DKGREY and BLACK *)
color := SUCC(CLR_VISIBLE1) + age;
CASE age OF
2 : gather_hidden_mines(scene, col, row, 1);
4 : gather_hidden_mines(scene, col, row, 2);
oldest_age-1,
oldest_age : color := oldest_age - age;
END; (* CASE *)
draw_block(x1, y1, x2, y2, color);
INC(age);
(* remove oldie mines *)
IF (age > oldest_age) THEN
first_mine := SUCC(mine);
END; (* WITH *)
INC(mine);
END; (* WHILE *)
UNTIL (first_mine > last_mine) OR ESC_pressed;
(* if player pressed ESC then don't show the score ... QUIT *)
IF (first_mine <= last_mine) THEN
GameStatus := QUIT;
IF (SoundIsON) THEN
NoSound;
SetViewPort(0, 0, GetMaxX, GetMaxY, ClipOFF);
ShowMouse;
END; (* explode *)